// elementFromPoint from ajax.org

if(!document.elementFromPoint){
	Array.prototype.copy = function(){
		var ar = new Array();
		for(var i=0;i<this.length;i++)
			ar[i] = this[i] && this[i].copy ? this[i].copy() : this[i];
	
		return ar;
	}
	
	Document.prototype.elementFromPointRemove = function(el){
		if(!this.RegElements) return;
		this.RegElements.remove(el);
	}
	
	Document.prototype.elementFromPointAdd = function(el){
		if(!this.RegElements) this.RegElements = [];
		this.RegElements.push(el);
	}
	
	Document.prototype.elementFromPointReset = function(RegElements){
		//define globals
		FoundValue = [];
		FoundNode = null;
		LastFoundAbs = document.documentElement;
	}
	
	Document.prototype.elementFromPoint = function(x, y){
		document.elementFromPointReset();
	
		// Optimization only looking at registered nodes
		if(this.RegElements){
			for(var calc_z=-1,calc,i=0;i<this.RegElements.length;i++){
				var n = this.RegElements[i];
				if(getStyle(n, "display") == "none") continue;
	
				var sx = getElementPosX(n); 
				var sy = getElementPosY(n);
				var ex = sx + n.offsetWidth; var ey = sy + n.offsetHeight;
				
				if(x > sx && x < ex && y > sy && y < ey){
					var z = getElementZindex(n);
					if(z > calc_z){ //equal z-indexes not supported
						calc = [n, x, y, sx, sy];
						calc_z = z;
					}
				}
			}
			
			if(calc){
				efpi(calc[0], calc[1], calc[2], 0, FoundValue, calc[3], calc[4]);
				if(!FoundNode){
					FoundNode = calc[0];
					LastFoundAbs = calc[0];
					FoundValue = [calc_z];
				}
			}
		}
		
		if(!this.RegElements || !this.RegElements.length)
			efpi(document.body, x, y, 0, [], getElementPosX(document.body), getElementPosY(document.body));
			
		return FoundNode;
	}
	
	function getStyle(el, prop) {
		return document.defaultView.getComputedStyle(el,'').getPropertyValue(prop);
	}
	
	function efpi(from, x, y, CurIndex, CurValue, px, py){
		var StartValue = CurValue;
		var StartIndex = CurIndex;
		
		//Loop through childNodes
		var nodes = from.childNodes;
		for(var n,i=0;i<from.childNodes.length;i++){
			n = from.childNodes[i];
			if( n.nodeType != Node.TEXT_NODE && getStyle(n, 'display') != 'none' ){
				var sx = px + n.offsetLeft - n.offsetParent.scrollLeft;
				var sy = py + n.offsetTop - n.offsetParent.scrollTop;
				var ex = sx + n.offsetWidth; var ey = sy + n.offsetHeight;
				
				//if(Child is position absolute/relative and overflow == "hidden" && !inSpace) continue;
				var isAbs = getStyle(n, "position");
				isAbs = isAbs == "absolute" || isAbs == "relative";
				var isHidden = getStyle(n, "overflow") == "hidden";
				var inSpace = (x > sx && x < ex && y > sy && y < ey);
				if(isAbs && isHidden && !inSpace) continue;
		
				CurIndex = StartIndex;
				CurValue = StartValue.copy();
		
				//if (Child is position absolute/relative and has zIndex) or overflow == "hidden"
				var z = parseInt(getStyle(n, "z-index"));
				if(isAbs && (z || z == 0) || isHidden){
					//if(!is position absolute/relative) zIndex = 0
					if(!isAbs) z = 0;
					
					//if zIndex >= FoundValue[CurIndex] 
					if(z >= (FoundValue[CurIndex] || 0)){
						//if zIndex > CurValue[CurIndex];
						if(z > (CurValue[CurIndex] || 0)){
							//CurValue = StartValue.copy();
							
							//set CurValue[CurIndex] = zIndex
							CurValue[CurIndex] = z;
						}
						
						CurIndex++
						
						//if(inSpace && CurIndex >= FoundValue.length)
						if(inSpace && CurIndex >= FoundValue.length){
							//Set FoundNode is currentNode
							FoundNode = n;
							//Set FoundValue is CurValue
							FoundValue = CurValue;//.copy();
							
							LastFoundAbs = n;
						}
					}
					//else continue; //Ignore this treedepth
					else continue;
				}
				//else if CurValue[CurIndex] continue; //Ignore this treedepth
				//else if(CurValue[CurIndex]) continue;
				else if(inSpace && CurIndex >= FoundValue.length){
					//Set FoundNode is currentNode
					FoundNode = n;
					//Set FoundValue is CurValue
					FoundValue = CurValue;//.copy();
				}
				
				//loop through childnodes recursively
				efpi(n, x, y, CurIndex, CurValue, isAbs ? sx : px, isAbs ? sy : py)
			}
		}
	}
	
	function getElementPosY(myObj){return myObj.offsetTop + parseInt(getStyle(myObj, "border-top-width")) + (myObj.offsetParent ? getElementPosY(myObj.offsetParent) : 0)}
	function getElementPosX(myObj){return myObj.offsetLeft + parseInt(getStyle(myObj, "border-left-width")) + (myObj.offsetParent ? getElementPosX(myObj.offsetParent) : 0)}
	function getElementZindex(myObj){
		//This is not quite sufficient and should be changed
		var z = 0, n, p = myObj;
		while(p && p.nodeType == 1){
			z = Math.max(z, parseInt(getStyle(p, "z-index")) || -1);
			p = p.parentNode;
		}
		return z;
	}
}